#include "common.hlsl"

VS_OUTPUT_SM VS_GenerateSceneSM( VS_INPUT_SCENE input )
{
    VS_OUTPUT_SM Output;
    
    // Transform the position from object space to homogeneous projection space
    Output.Position = mul( float4(input.Position, 1), g_mViewProjLight );
    
	// output position
	Output.texPos = input.Position;
    
    return Output;    
}

VS_OUTPUT_SCENE VS_RenderScene( VS_INPUT_SCENE input )
{
    VS_OUTPUT_SCENE Output;
    
    // Transform the position from object space to homogeneous projection space
    Output.Position = mul( float4(input.Position, 1), g_mViewProj );
    
	// output tangent and texture coordinate value
	Output.Normal = input.Normal;
	Output.Texcoord = input.Texcoord;

	// output position
	Output.texPos = input.Position;
    
    return Output;    
}


//basic phong shading
float4 PhongShading(float3 iPos, float3 iNormal, float2 tex, float amountLight)
{
	// define ambient, diffuse and specular term for material
	float4 matAmbient = g_MatAmbient;
	float4 matDiffuse = float4(g_MatDiffuse.xyz, 1);
	float4 matSpecular = float4(g_MatSpecular.xyz, 1);
	float exponent = g_MatSpecular.w;

	if(g_MatDiffuse.w > 0)
	{
		float4 texColor = g_txObj.Sample( g_samLinearWrap, tex );
		matAmbient *= texColor;
		matDiffuse *= texColor;
	}

	float3 lightPos = g_PointLightPos.xyz;
	float3 vLightDir = normalize(lightPos - iPos);
	float3 normal = normalize(iNormal);

	float LDotN = dot(normal, vLightDir);
	float vDiffuse = max(0, LDotN);
	
	float3 vEyeDir = normalize(g_vEye.xyz - iPos.xyz);
	float3 vHalf = normalize(vEyeDir + vLightDir);
	float HDotN = dot(vHalf, normal);
	float vSpecular = max(0, HDotN);

	float4 vColor = matAmbient * g_AmbientLightColor + amountLight * 
		g_PointLightColor *	( matDiffuse * vDiffuse  + matSpecular * pow(vSpecular, exponent));

	return vColor;
}

float4 SceneColor(float2 tex, float amountLight)
{
	//////////////////////////////////////////////////////////////////////////////////////////////
	// shading
	// define ambient, diffuse and specular term for material
	float4 matDiffuse = float4(g_MatDiffuse.xyz, 1);

	if(g_MatDiffuse.w > 0)
	{
		float4 texColor = g_txObj.Sample( g_samLinearWrap, tex );
		matDiffuse *= texColor;
    }

	float4 vColor = matDiffuse * amountLight;
	return vColor;
}

struct PS_OUTPUT_COLOR_DEPTH
{
	float4 color : SV_Target0;
	float depth: SV_Target1;
};

PS_OUTPUT_COLOR_DEPTH PS_RenderSceneShading_Depth(VS_OUTPUT_SCENE input )
{

	PS_OUTPUT_COLOR_DEPTH output;

	float4 projPos = mul( float4(input.texPos, 1), g_mViewProj);
	float depth = projPos.z/ projPos.w;

	output.color = PhongShading(input.texPos, input.Normal, input.Texcoord, 1);
	output.depth = depth;

	return output;
}

float4 ComputeSceneShading(float3 pos, float3 normal, float2 tex, float amountLight, int tech)
{
	float4 color = float4(1, 0, 0, 1);
	switch(tech)
	{
		// for scene ojects, simply use phone model for shading
	case SHADING_KAJIYA:
		color = PhongShading(pos, normal, tex, amountLight);
		break;
	default:
		color = SceneColor(tex, amountLight);
		break;
	}
	return color;
}

[earlydepthstencil]
float4 PS_RenderScene(VS_OUTPUT_SCENE input):SV_Target
{
	INPUT_SHADOW inShadow;
	inShadow.pos = input.texPos;
	AmountLight amountLight = ComputeShadow(inShadow, g_iTechSM);
	// for opaque object, we only cast shadow from hair
	float light = amountLight.amountLight_scene; //
	float4 color = ComputeSceneShading(input.texPos, input.Normal, input.Texcoord, 
										light, g_iTechShading);	
	return color;
}

//////////////////////////////////////////////////////////////////////////
// for modeling view only
float4 PS_SceneShading(VS_OUTPUT_SCENE input ): SV_Target
{
	return PhongShading(input.texPos, input.Normal, input.Texcoord, 1);
}
